/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.jsrpc.core;

import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.Properties;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.jsrpc.servlet.SessionBean;
import org.jsrpc.vo.CallMethod;
import org.jsrpc.vo.Parameter;

/**
 *
 * @author neo
 */
public class Remote {

    Logger log = Logger.getLogger(this.getClass().getName());
    private Properties prop = null;
    private ParserObject parserObject = null;

    public Remote() {
        prop = new Properties();
        try {
            prop.load(this.getClass().getResourceAsStream("/configure.properties"));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        parserObject = new ParserObject(prop);
    }

    public String invoke(String className, CallMethod callMethod,
            ServletContext context, HttpServletRequest request) {
        log.info("Remote invoke.");
        try {
            log.info("Start Remote{ object[" + callMethod.getClassName() + "]Method[" + callMethod.getName() + "]");
            Object obj = Class.forName(className).newInstance();
            Class cSuple = obj.getClass().getSuperclass();
            if (cSuple != null) {
                log.info("In Session Bean not null.");
                if (cSuple.getName().equals("org.jsrpc.servlet.SessionBean")) {
                    log.info("In Session Bean.");
                    SessionBean bean = (SessionBean) obj;
                    bean.setContext(context);
                    bean.setHttpRequest(request);
                }
            }
            String methodName = callMethod.getName();
            Class class_params[] = new Class[callMethod.getParameterSize()];
            Object obj_params[] = new Object[callMethod.getParameterSize()];
            for (int i = 0; i < callMethod.getParameterSize(); i++) {
                Parameter param = callMethod.getParameter(i);
                log.info("Parameter[" + param.getNameType() + "]");
                log.info("ParameterValue["+ param.getValue() +"]");
                int inCase = 0;
                String scase = prop.getProperty(param.getNameType() + ".ptype");
                if (scase == null) {
                    inCase = -1;
                } else {
                    inCase = Integer.parseInt(scase);
                }
                switch (inCase) {
                    case 0:
                        break;
                    case 1:
                        if( param.getValue().indexOf("-") == 4 
                                && param.getValue().indexOf(":") > 0 ) {
                            class_params[i] = java.util.Date.class;
                            SimpleDateFormat sm = new SimpleDateFormat(prop.getProperty("date.format"));
                            obj_params[i] = sm.parse(param.getValue());
                        } else {
                            class_params[i] = String.class;
                            obj_params[i] = param.getValue();
                        }
                        break;
                    case 2:
                        class_params[i] = int.class;
                        obj_params[i] = Integer.parseInt(param.getValue());
                        break;
                    case 3:
                        class_params[i] = long.class;
                        obj_params[i] = Long.parseLong(param.getValue());
                        break;
                    case 4:
                        class_params[i] = double.class;
                        obj_params[i] = Double.parseDouble(param.getValue());
                        break;
                    case 5:
                        class_params[i] = float.class;
                        obj_params[i] = Float.parseFloat(param.getValue());
                        break;
                    case 6:
                        class_params[i] = java.util.Date.class;
                        SimpleDateFormat sm = new SimpleDateFormat(prop.getProperty("date.format"));
                        obj_params[i] = sm.parse(param.getValue());
                        break;
                    case 7:
                        class_params[i] = boolean.class;
                        obj_params[i] = Boolean.parseBoolean(param.getValue());
                        break;
                    case 8:
                        class_params[i] = java.util.Date.class;
                        SimpleDateFormat sf = new SimpleDateFormat(prop.getProperty("date.format"));
                        obj_params[i] = sf.parse(param.getValue());
                        break;
                    case 9:
                        class_params[i] = Integer.class;
                        obj_params[i] = new Integer(param.getValue());
                        break;
                    default:
                        log.info("Prepare invoke object.["+ param.getValue() +"]");
                        String strDecode = URLDecoder.decode(param.getValue(), "UTF-8");
                        log.info("strDecode["+ strDecode +"]");
                        String classParam = parserObject.getObjectName(strDecode);
                        class_params[i] = Class.forName(classParam);
                        obj_params[i] = parserObject.setObject(strDecode);
                        break;
                }
            }
            //log.info("Invoke method of object.");
            Method method = obj.getClass().getDeclaredMethod(methodName, class_params);
            log.info("method name[" + method.getName() + "]");
            for (int i = 0; i < obj_params.length; i++) {
                Object opm = obj_params[i];
                log.info("param name:" + i + "[" + opm.getClass().getName() + "]");
            }

            Object objReturn = method.invoke(obj, obj_params);
            if (objReturn != null) {
                log.info("End remote return[" + objReturn.getClass().getName() + "] }");
            } else {
                log.info("End remote return[void] }");
                return "";
            }
            log.info("Parse object to client.");
            String returnString = parseObjectToString(objReturn);
            System.out.println("return[" + returnString + "]");
            return (returnString == null) ? "" : returnString;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    public String parseObjectToString(Object reObj) throws Exception {
        String className = reObj.getClass().getName();
        System.out.println("=--------class Name["+ className +"]-----------");
        String sCase = prop.getProperty(className + ".return.ptype");
        sCase = (sCase == null) ? "-1" : sCase;
        int iCase = Integer.parseInt(sCase);
        switch (iCase) {
            case 0:
                return "";
            case 1: //String
                //System.out.println("[String return]");
                return (String) reObj;
            case 2: //int
                return ((Integer) reObj).toString();
            case 3: //long
                return ((Long) reObj).toString();
            case 4: //double
                return ((Double) reObj).toString();
            case 5: //float
                return ((Float) reObj).toString();
            case 6: //Date
                java.util.Date date = ((java.util.Date) reObj);
                SimpleDateFormat sd = new SimpleDateFormat(prop.getProperty("date.format"));
                return sd.format(date);
            case 7: //boolean
                return ((Boolean) reObj).toString();
            case 9: //int
                return ((Integer) reObj).toString();    
            default:
                log.info("Parse selection object.");
                //System.out.println("[Object return]["+ className+"]");
                String handle = prop.getProperty(className + ".return");
                //System.out.println("[Object return]["+ handle +"]");
                handle = (handle == null) ? prop.getProperty("default.return") : handle;
                //System.out.println("[Object return]["+ handle+"]");
                ObjectToStringHandler objHandle = (ObjectToStringHandler) Class.forName(handle).newInstance();
                return objHandle.toString(reObj, prop);
        }
    }
}
